home *** CD-ROM | disk | FTP | other *** search
/ Isometric Game Programming with DirectX 7.0 / Isometric Game Programming.iso / source / chapter9 / isohex9_1 / isohex9_1.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-03  |  18.9 KB  |  888 lines

  1. /*****************************************************************************
  2. IsoHex9_1.cpp
  3. Ernest S. Pazera
  4. 30MAY2000
  5. Start a WIN32 Application Workspace, add in this file
  6. Requires winmm.lib, ddraw.lib, dxguid.lib, dsound.lib
  7. Needs dsound.h, ddraw.h, mmsystem.h
  8. Needs DDFuncs.h/cpp, DSFuncs.h/cpp, GDICanvas.h/cpp, WAVLoader.h/cpp
  9. *****************************************************************************/
  10.  
  11. //////////////////////////////////////////////////////////////////////////////
  12. //INCLUDES
  13. //////////////////////////////////////////////////////////////////////////////
  14. #define WIN32_LEAN_AND_MEAN  
  15.  
  16. #include <windows.h>
  17. #include <mmsystem.h>
  18. #include "ddraw.h"
  19. #include "dsound.h"
  20. #include "GDICanvas.h"
  21. #include "DDFuncs.h"
  22. #include "DSFuncs.h"
  23.  
  24. //////////////////////////////////////////////////////////////////////////////
  25. //DEFINES/CONSTANTS
  26. //////////////////////////////////////////////////////////////////////////////
  27. //name for our window class
  28. #define WINDOWCLASS "ISOHEX9"
  29. //title of the application
  30. #define WINDOWTITLE "IsoHex 9-1"
  31.  
  32. //cound information
  33. const int SOUNDCOUNT=9;//number of sounds in game
  34. const int SOUNDCOPYCOUNT=4;//number of copies of sounds in game
  35. const int SND_BOUNCE=0;
  36. const int SND_LOSE=1;
  37. const int SND_HIT=2;
  38. const int SND_WIN=8;
  39.  
  40. //ball dimensions
  41. const int BALLWIDTH=8;
  42. const int BALLHEIGHT=8;
  43.  
  44. //paddle dimensions
  45. const int PADDLEWIDTH=64;
  46. const int PADDLEHEIGHT=16;
  47.  
  48. //brick dimensions
  49. const int BRICKWIDTH=32;
  50. const int BRICKHEIGHT=16;
  51. const int BRICKCOUNT=6;
  52.  
  53. //screen dimensions
  54. const int SCREENWIDTH=640;
  55. const int SCREENHEIGHT=480;
  56. const int SCREENBPP=16;
  57.  
  58. //brick map
  59. const int MAPCOLUMNCOUNT=SCREENWIDTH/BRICKWIDTH;//number of bricks per row
  60. const int MAPROWCOUNT=12;//number of rows
  61. const int MAPOFFSET=64;//pixel offset from top of screen
  62.  
  63. //game states
  64. enum GAMESTATE {GS_START,GS_STARTWAIT,GS_PLAY,GS_DEAD,GS_RESET,GS_WINLEVEL,GS_LOSEGAME};
  65.  
  66. //////////////////////////////////////////////////////////////////////////////
  67. //PROTOTYPES
  68. //////////////////////////////////////////////////////////////////////////////
  69. bool Prog_Init();//game data initalizer
  70. void Prog_Loop();//main game loop
  71. void Prog_Done();//game clean up
  72.  
  73. //initialization functions
  74. void DD_Init();
  75. void DS_Init();
  76.  
  77. //cleanup functions
  78. void DD_Done();
  79. void DS_Done();
  80.  
  81. //game functions
  82. void SetUpGame();
  83. void ResetGame();
  84. void ShowBoard();
  85. void DrawBrick(int x, int y, int bricknum);
  86. void DrawPaddle();
  87. void DrawBall();
  88. void MoveBall();
  89. void SoundPlay(int sound);
  90. void ShowScore();
  91. void ShowLives();
  92.  
  93. //////////////////////////////////////////////////////////////////////////////
  94. //GLOBALS
  95. //////////////////////////////////////////////////////////////////////////////
  96. HINSTANCE hInstMain=NULL;//main application handle
  97. HWND hWndMain=NULL;//handle to our main window
  98.  
  99. //direct draw variables
  100. LPDIRECTDRAW7 lpdd=NULL;//main controller
  101. LPDIRECTDRAWSURFACE7 lpddsprime=NULL;//primary surface
  102. LPDIRECTDRAWSURFACE7 lpddsback=NULL;//back buffer
  103. LPDIRECTDRAWSURFACE7 lpddsball=NULL;//ball
  104. LPDIRECTDRAWSURFACE7 lpddspaddle=NULL;//paddle
  105. LPDIRECTDRAWSURFACE7 lpddsbricks=NULL;//bricks
  106.  
  107. //other graphical objects
  108. HFONT hfntMain=NULL;
  109.  
  110. //direct sound variables
  111. LPDIRECTSOUND lpds=NULL;//main sound controller
  112. LPDIRECTSOUNDBUFFER lpdsb[SOUNDCOUNT][SOUNDCOPYCOUNT];//sounds
  113. DWORD dwSoundCopy[SOUNDCOUNT];//which copy of any given sound is next to be played
  114. LPDIRECTSOUNDBUFFER lpdsbMusic=NULL;
  115. LPDIRECTSOUNDBUFFER lpdsbOoYeah=NULL;
  116. LPDIRECTSOUNDBUFFER lpdsbGroovy=NULL;
  117. LPDIRECTSOUNDBUFFER lpdsbLoveThing=NULL;
  118.  
  119. //main game state
  120. GAMESTATE GameState=GS_START;
  121.  
  122. //game variables
  123. int Board[MAPCOLUMNCOUNT][MAPROWCOUNT];
  124. DWORD dwScore=0;
  125. DWORD dwLives=0;
  126. DWORD dwBrickCount=0;
  127. DWORD dwBricksHit=0;
  128.  
  129. //paddle position
  130. POINT ptPaddle;
  131.  
  132. //ball position
  133. POINT ptBall;
  134. POINT ptBallNext;
  135. POINT ptBallVel;
  136. bool bHitTop=false;
  137.  
  138. //////////////////////////////////////////////////////////////////////////////
  139. //WINDOWPROC
  140. //////////////////////////////////////////////////////////////////////////////
  141. LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
  142. {
  143.     //which message did we get?
  144.     switch(uMsg)
  145.     {
  146.     case WM_LBUTTONDOWN:
  147.         {
  148.             switch(GameState)
  149.             {
  150.             case GS_STARTWAIT:
  151.                 {
  152.                     GameState=GS_PLAY;
  153.                 }break;
  154.             default:
  155.                 {
  156.                 }break;
  157.             }
  158.         }break;
  159.     case WM_MOUSEMOVE:
  160.         {
  161.             ptPaddle.x=LOWORD(lParam)-PADDLEWIDTH/2;
  162.             if(ptPaddle.x<0) ptPaddle.x=0;
  163.             if(ptPaddle.x>SCREENWIDTH-PADDLEWIDTH) ptPaddle.x=SCREENWIDTH-PADDLEWIDTH;
  164.         }break;
  165.     case WM_DESTROY://the window is being destroyed
  166.         {
  167.  
  168.             //tell the application we are quitting
  169.             PostQuitMessage(0);
  170.  
  171.             //handled message, so return 0
  172.             return(0);
  173.  
  174.         }break;
  175.     case WM_PAINT://the window needs repainting
  176.         {
  177.             //a variable needed for painting information
  178.             PAINTSTRUCT ps;
  179.             
  180.             //start painting
  181.             HDC hdc=BeginPaint(hwnd,&ps);
  182.  
  183.             /////////////////////////////
  184.             //painting code would go here
  185.             /////////////////////////////
  186.  
  187.             //end painting
  188.             EndPaint(hwnd,&ps);
  189.                         
  190.             //handled message, so return 0
  191.             return(0);
  192.         }break;
  193.     }
  194.  
  195.     //pass along any other message to default message handler
  196.     return(DefWindowProc(hwnd,uMsg,wParam,lParam));
  197. }
  198.  
  199.  
  200. //////////////////////////////////////////////////////////////////////////////
  201. //WINMAIN
  202. //////////////////////////////////////////////////////////////////////////////
  203. int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
  204. {
  205.     //assign instance to global variable
  206.     hInstMain=hInstance;
  207.  
  208.     //create window class
  209.     WNDCLASSEX wcx;
  210.  
  211.     //set the size of the structure
  212.     wcx.cbSize=sizeof(WNDCLASSEX);
  213.  
  214.     //class style
  215.     wcx.style=CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
  216.  
  217.     //window procedure
  218.     wcx.lpfnWndProc=TheWindowProc;
  219.  
  220.     //class extra
  221.     wcx.cbClsExtra=0;
  222.  
  223.     //window extra
  224.     wcx.cbWndExtra=0;
  225.  
  226.     //application handle
  227.     wcx.hInstance=hInstMain;
  228.  
  229.     //icon
  230.     wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);
  231.  
  232.     //cursor
  233.     wcx.hCursor=LoadCursor(NULL,IDC_ARROW);
  234.  
  235.     //background color
  236.     wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
  237.  
  238.     //menu
  239.     wcx.lpszMenuName=NULL;
  240.  
  241.     //class name
  242.     wcx.lpszClassName=WINDOWCLASS;
  243.  
  244.     //small icon
  245.     wcx.hIconSm=NULL;
  246.  
  247.     //register the window class, return 0 if not successful
  248.     if(!RegisterClassEx(&wcx)) return(0);
  249.  
  250.     //create main window
  251.     hWndMain=CreateWindowEx(0,WINDOWCLASS,WINDOWTITLE, WS_POPUP | WS_VISIBLE,0,0,320,240,NULL,NULL,hInstMain,NULL);
  252.  
  253.     //error check
  254.     if(!hWndMain) return(0);
  255.  
  256.     //if program initialization failed, then return with 0
  257.     if(!Prog_Init()) return(0);
  258.  
  259.     //message structure
  260.     MSG msg;
  261.  
  262.     //message pump
  263.     for(;;)    
  264.     {
  265.         //look for a message
  266.         if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  267.         {
  268.             //there is a message
  269.  
  270.             //check that we arent quitting
  271.             if(msg.message==WM_QUIT) break;
  272.             
  273.             //translate message
  274.             TranslateMessage(&msg);
  275.  
  276.             //dispatch message
  277.             DispatchMessage(&msg);
  278.         }
  279.  
  280.         //run main game loop
  281.         Prog_Loop();
  282.     }
  283.     
  284.     //clean up program data
  285.     Prog_Done();
  286.  
  287.     //return the wparam from the WM_QUIT message
  288.     return(msg.wParam);
  289. }
  290.  
  291. //////////////////////////////////////////////////////////////////////////////
  292. //INITIALIZATION
  293. //////////////////////////////////////////////////////////////////////////////
  294. bool Prog_Init()
  295. {
  296.     //hide the cursor
  297.     ShowCursor(FALSE);
  298.  
  299.     //initialize direct draw
  300.     DD_Init();
  301.  
  302.     //initialize direct sound
  303.     DS_Init();
  304.  
  305.     //set initial gamestate
  306.     GameState=GS_START;
  307.  
  308.     return(true);//return success
  309. }
  310.  
  311. //////////////////////////////////////////////////////////////////////////////
  312. //CLEANUP
  313. //////////////////////////////////////////////////////////////////////////////
  314. void Prog_Done()
  315. {
  316.     //clean up direct draw
  317.     DD_Done();
  318.  
  319.     //clean up direct sound
  320.     DS_Done();
  321.  
  322.     //show the cursor
  323.     ShowCursor(TRUE);
  324. }
  325.  
  326. //////////////////////////////////////////////////////////////////////////////
  327. //MAIN GAME LOOP
  328. //////////////////////////////////////////////////////////////////////////////
  329. void Prog_Loop()
  330. {
  331.     switch(GameState)
  332.     {
  333.     case GS_START:
  334.         {
  335.             dwScore=0;
  336.             dwLives=3;
  337.             SetUpGame();
  338.             GameState=GS_STARTWAIT;
  339.         }break;
  340.     case GS_STARTWAIT:
  341.         {
  342.             ShowBoard();
  343.             lpddsprime->Flip(NULL,DDFLIP_WAIT);
  344.         }break;
  345.     case GS_PLAY:
  346.         {
  347.             //limit frame time
  348.             DWORD dwTimeStart=GetTickCount();
  349.  
  350.             //move ball
  351.             MoveBall();
  352.  
  353.             //show board
  354.             ShowBoard();
  355.  
  356.             //show frame
  357.             lpddsprime->Flip(NULL,DDFLIP_WAIT);
  358.  
  359.             //wait for 10 ms to elapse
  360.             while(GetTickCount()-dwTimeStart<10);
  361.         }break;
  362.     case GS_DEAD:
  363.         {
  364.             dwLives--;
  365.             if(dwLives)
  366.             {
  367.                 GameState=GS_RESET;
  368.             }
  369.             else
  370.             {
  371.                 GameState=GS_LOSEGAME;
  372.             }
  373.         }break;
  374.     case GS_RESET:
  375.         {
  376.             ResetGame();
  377.             GameState=GS_STARTWAIT;
  378.         }break;
  379.     case GS_WINLEVEL:
  380.         {
  381.             SetUpGame();
  382.             GameState=GS_STARTWAIT;
  383.         }break;
  384.     case GS_LOSEGAME:
  385.         {
  386.             GameState=GS_START;
  387.         }break;
  388.     }
  389. }
  390.  
  391. //initialize direct draw vars
  392. void DD_Init()
  393. {
  394.     //create direct draw object
  395.     lpdd=LPDD_Create(hWndMain,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
  396.  
  397.     //set display
  398.     lpdd->SetDisplayMode(SCREENWIDTH,SCREENHEIGHT,SCREENBPP,0,0);
  399.  
  400.     //create primary surface, with one back buffer
  401.     lpddsprime=LPDDS_CreatePrimary(lpdd,1);
  402.  
  403.     //get back buffer
  404.     lpddsback=LPDDS_GetSecondary(lpddsprime);
  405.  
  406.     //add font
  407.     AddFontResource("paganini.ttf");
  408.  
  409.     //create font
  410.     hfntMain=CreateFont(30,0,0,0,0,0,0,0,0,0,0,0,0,"Paganini");
  411.  
  412.     //create offscreen surfaces
  413.     //ball
  414.     lpddsball=LPDDS_LoadFromFile(lpdd,"IsoHex9_1-2.bmp");
  415.     LPDDS_SetSrcColorKey(lpddsball,0);
  416.  
  417.     //paddle
  418.     lpddspaddle=LPDDS_LoadFromFile(lpdd,"IsoHex9_1-3.bmp");
  419.  
  420.     //bricks
  421.     lpddsbricks=LPDDS_LoadFromFile(lpdd,"IsoHex9_1-1.bmp");
  422.  
  423.     //clear out back buffer
  424.     DDBLTFX ddbltfx;
  425.     DDBLTFX_ColorFill(&ddbltfx,0);
  426.     lpddsback->Blt(NULL,NULL,NULL,DDBLT_WAIT | DDBLT_COLORFILL,&ddbltfx);
  427. }
  428.  
  429. //initialize direct sound vars
  430. void DS_Init()
  431. {
  432.     //create sound manager
  433.     DirectSoundCreate(NULL,&lpds,NULL);
  434.  
  435.     //cooperate with main window
  436.     lpds->SetCooperativeLevel(hWndMain,DSSCL_NORMAL);
  437.  
  438.     //load sounds
  439.     lpdsb[0][0]=LPDSB_LoadFromFile(lpds,"bounce.wav",0);
  440.     lpdsb[1][0]=LPDSB_LoadFromFile(lpds,"lose.wav",0);
  441.     lpdsb[2][0]=LPDSB_LoadFromFile(lpds,"hit5.wav",0);
  442.     lpdsb[3][0]=LPDSB_LoadFromFile(lpds,"hit4.wav",0);
  443.     lpdsb[4][0]=LPDSB_LoadFromFile(lpds,"hit3.wav",0);
  444.     lpdsb[5][0]=LPDSB_LoadFromFile(lpds,"hit2.wav",0);
  445.     lpdsb[6][0]=LPDSB_LoadFromFile(lpds,"hit1.wav",0);
  446.     lpdsb[7][0]=LPDSB_LoadFromFile(lpds,"hit0.wav",0);
  447.     lpdsb[8][0]=LPDSB_LoadFromFile(lpds,"win.wav",0);
  448.  
  449.     //load music
  450.     lpdsbMusic=LPDSB_LoadFromFile(lpds,"music.wav",0);
  451.  
  452.     //load vox
  453.     lpdsbOoYeah=LPDSB_LoadFromFile(lpds,"ooyeah.wav",0);
  454.     lpdsbGroovy=LPDSB_LoadFromFile(lpds,"groovy.wav",0);
  455.     lpdsbLoveThing=LPDSB_LoadFromFile(lpds,"lovething.wav",0);
  456.     
  457.     //duplicate sounds
  458.     for(int copy=1;copy<SOUNDCOPYCOUNT;copy++)
  459.     {
  460.         for(int sound=0;sound<SOUNDCOUNT;sound++)
  461.         {
  462.             lpds->DuplicateSoundBuffer(lpdsb[sound][0],&lpdsb[sound][copy]);
  463.         }
  464.     }
  465.  
  466.     //start music
  467.     lpdsbMusic->Play(0,0,DSBPLAY_LOOPING);
  468. }
  469.  
  470. //clean up directdraw vars
  471. void DD_Done()
  472. {
  473.     //release surfaces
  474.     LPDDS_Release(&lpddspaddle);
  475.     LPDDS_Release(&lpddsbricks);
  476.     LPDDS_Release(&lpddsball);
  477.     LPDDS_Release(&lpddsprime);
  478.  
  479.     //release direct draw object
  480.     LPDD_Release(&lpdd);
  481.  
  482.     //delete the font
  483.     DeleteObject(hfntMain);
  484.  
  485.     //remove font resource
  486.     RemoveFontResource("Paganini.ttf");
  487. }
  488.  
  489. //clean up directsound vars
  490. void DS_Done()
  491. {
  492.     //release all sounds and copies of sounds
  493.     for(int copy=0;copy<SOUNDCOPYCOUNT;copy++)
  494.     {
  495.         for(int sound=0;sound<SOUNDCOUNT;sound++)
  496.         {
  497.             LPDSB_Release(&lpdsb[sound][copy]);
  498.         }
  499.     }
  500.  
  501.     //release music
  502.     LPDSB_Release(&lpdsbMusic);
  503.  
  504.     //release vox
  505.     LPDSB_Release(&lpdsbOoYeah);
  506.     LPDSB_Release(&lpdsbLoveThing);
  507.     LPDSB_Release(&lpdsbGroovy);
  508.  
  509.     //release directsound object
  510.     if(lpds)
  511.     {
  512.         lpds->Release();
  513.         lpds=NULL;
  514.     }
  515. }
  516.  
  517. void SetUpGame()
  518. {
  519.     //reinitialize brick count
  520.  
  521.     //loop through every board location
  522.     for(int x=0;x<MAPCOLUMNCOUNT;x++)
  523.     {
  524.         for(int y=0;y<MAPROWCOUNT;y++)
  525.         {
  526.             //set the brick
  527.             Board[x][y]=y/(MAPROWCOUNT/BRICKCOUNT);
  528.             dwBrickCount++;
  529.         }
  530.     }
  531.     //paddle position
  532.     ptPaddle.x=SCREENWIDTH/2-PADDLEWIDTH/2;
  533.     ptPaddle.y=SCREENHEIGHT-PADDLEHEIGHT;
  534.  
  535.     //ball position and speed
  536.     ptBall.x=SCREENWIDTH/2-BALLWIDTH/2;
  537.     ptBall.y=300;
  538.     ptBallNext=ptBall;
  539.     ptBallVel.x=3;
  540.     ptBallVel.y=3;
  541.     bHitTop=false;
  542. }
  543.  
  544. //reset game after a death
  545. void ResetGame()
  546. {
  547.     //ball position and speed
  548.     ptBall.x=SCREENWIDTH/2-BALLWIDTH/2;
  549.     ptBall.y=300;
  550.     ptBallNext=ptBall;
  551.     ptBallVel.x=3;
  552.     ptBallVel.y=3;
  553.     bHitTop=false;
  554. }
  555.  
  556.  
  557. void ShowBoard()
  558. {
  559.     //clear out back buffer
  560.     DDBLTFX ddbltfx;
  561.     DDBLTFX_ColorFill(&ddbltfx,0);
  562.     lpddsback->Blt(NULL,NULL,NULL,DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx);
  563.  
  564.     //loop through every board location
  565.     for(int x=0;x<MAPCOLUMNCOUNT;x++)
  566.     {
  567.         for(int y=0;y<MAPROWCOUNT;y++)
  568.         {
  569.             //draw the brick
  570.             if(Board[x][y]!=-1) DrawBrick(x*BRICKWIDTH,y*BRICKHEIGHT+MAPOFFSET,Board[x][y]);
  571.         }
  572.     }
  573.  
  574.     //draw the paddle
  575.     DrawPaddle();
  576.  
  577.     //draw the ball
  578.     DrawBall();
  579.  
  580.     //show the score
  581.     ShowScore();
  582.  
  583.     //show number of lives left
  584.     ShowLives();
  585. }
  586.  
  587. void DrawBrick(int x, int y, int bricknum)
  588. {
  589.     //source and destination rectangles
  590.     RECT rcDst;
  591.     RECT rcSrc;
  592.  
  593.     //set source rectangle
  594.     SetRect(&rcSrc,0,BRICKHEIGHT*bricknum,BRICKWIDTH,BRICKHEIGHT*bricknum+BRICKHEIGHT);
  595.  
  596.     //set destination rectangle
  597.     CopyRect(&rcDst,&rcSrc);
  598.     OffsetRect(&rcDst,x-rcDst.left,y-rcDst.top);
  599.  
  600.     //blit the brick
  601.     lpddsback->Blt(&rcDst,lpddsbricks,&rcSrc,DDBLT_WAIT,NULL);
  602. }
  603.  
  604. void DrawPaddle()
  605. {
  606.     //set up source rect
  607.     RECT rcSrc;
  608.     SetRect(&rcSrc,0,0,PADDLEWIDTH,PADDLEHEIGHT);
  609.  
  610.     //set up dest rect
  611.     RECT rcDst;
  612.     CopyRect(&rcDst,&rcSrc);
  613.     OffsetRect(&rcDst,ptPaddle.x,ptPaddle.y);
  614.  
  615.     //blit
  616.     lpddsback->Blt(&rcDst,lpddspaddle,&rcSrc,DDBLT_WAIT,NULL);
  617. }
  618.  
  619. void DrawBall()
  620. {
  621.     //declare rects
  622.     RECT rcSrc;
  623.     RECT rcDst;
  624.  
  625.     //set up source rect
  626.     SetRect(&rcSrc,0,0,BALLWIDTH,BALLHEIGHT);
  627.  
  628.     //set up dest rect
  629.     CopyRect(&rcDst,&rcSrc);
  630.     OffsetRect(&rcDst,ptBall.x,ptBall.y);
  631.  
  632.     //blit
  633.     lpddsback->Blt(&rcDst,lpddsball,&rcSrc,DDBLT_WAIT | DDBLT_KEYSRC,NULL);
  634. }
  635.  
  636. void MoveBall()
  637. {
  638.     //determine next position of ball
  639.     ptBallNext.x=ptBall.x+ptBallVel.x*(bHitTop?2:1);
  640.     ptBallNext.y=ptBall.y+ptBallVel.y*(bHitTop?2:1);
  641.  
  642.     //bounds checking
  643.     if(ptBallNext.y<=0)
  644.     {
  645.         bHitTop=true;
  646.         ptBallNext.y=0;
  647.         ptBallVel.y=abs(ptBallVel.y);
  648.         SoundPlay(SND_BOUNCE);
  649.     }
  650.     if(ptBallNext.x<=0)
  651.     {
  652.         ptBallNext.x=0;
  653.         ptBallVel.x=abs(ptBallVel.x);
  654.         SoundPlay(SND_BOUNCE);
  655.     }
  656.     if(ptBallNext.y>=(SCREENHEIGHT-BALLHEIGHT))
  657.     {
  658.         ptBallNext.y=SCREENHEIGHT-BALLHEIGHT;
  659.         ptBallVel.y=-abs(ptBallVel.y);
  660.         SoundPlay(SND_LOSE);
  661.         GameState=GS_DEAD;
  662.     }
  663.     if(ptBallNext.x>=(SCREENWIDTH-BALLWIDTH))
  664.     {
  665.         ptBallNext.x=SCREENWIDTH-BALLWIDTH;
  666.         ptBallVel.x=-abs(ptBallVel.x);
  667.         SoundPlay(SND_BOUNCE);
  668.     }
  669.  
  670.     //collision test
  671.     int x;
  672.     int y;
  673.     bool hit=false;
  674.     RECT rcBall;
  675.     RECT rcBrick;
  676.     RECT rcIntersect;
  677.  
  678.     //bounding box for ball
  679.     SetRect(&rcBall,ptBallNext.x,ptBallNext.y,ptBallNext.x+BALLWIDTH,ptBallNext.y+BALLHEIGHT);
  680.  
  681.     for(x=0;x<MAPCOLUMNCOUNT;x++)
  682.     {
  683.         for(y=0;y<MAPROWCOUNT;y++)
  684.         {
  685.             if(Board[x][y]!=-1)
  686.             {
  687.                 //bounding rectangle
  688.                 SetRect(&rcBrick,x*BRICKWIDTH,y*BRICKHEIGHT+MAPOFFSET,x*BRICKWIDTH+BRICKWIDTH,y*BRICKHEIGHT+MAPOFFSET+BRICKHEIGHT);
  689.  
  690.                 //check for collision
  691.                 IntersectRect(&rcIntersect,&rcBall,&rcBrick);
  692.  
  693.                 //if collision detected
  694.                 if(!IsRectEmpty(&rcIntersect))
  695.                 {
  696.                     //play hit sound
  697.                     SoundPlay(Board[x][y]+SND_HIT);
  698.  
  699.                     //add to scroe
  700.                     dwScore+=(6-Board[x][y]);
  701.  
  702.                     //decrease brick count
  703.                     dwBrickCount--;
  704.  
  705.                     //if no bricks remaining
  706.                     if(dwBrickCount==0)
  707.                     {
  708.                         SoundPlay(SND_WIN);
  709.                         GameState=GS_WINLEVEL;
  710.                     }
  711.  
  712.                     //delete brick
  713.                     Board[x][y]=-1;
  714.  
  715.                     //set hit flag
  716.                     hit=true;
  717.  
  718.                     //increment bricks hit
  719.                     dwBricksHit++;
  720.  
  721.                     if(dwBricksHit==10)
  722.                     {
  723.                     //depending on number hit, play sound
  724.                     switch(rand()%3)
  725.                     {
  726.                     case 0:
  727.                         {
  728.                             lpdsbOoYeah->Play(0,0,0);
  729.                         }break;
  730.                     case 1:
  731.                         {
  732.                             lpdsbGroovy->Play(0,0,0);
  733.                         }break;
  734.                     case 2:
  735.                         {
  736.                             lpdsbLoveThing->Play(0,0,0);
  737.                         }break;
  738.                     }
  739.                     }
  740.                 }
  741.             }
  742.         }
  743.     }
  744.  
  745.     //if the hit flag was set
  746.     if(hit)
  747.     {
  748.         //bounce the ball
  749.         ptBallVel.y=-ptBallVel.y;
  750.     }
  751.  
  752.     //check for paddle collision
  753.     if(ptBallVel.y>0)
  754.     {
  755.         //paddle bounding rect
  756.         SetRect(&rcBrick,ptPaddle.x,ptPaddle.y,ptPaddle.x+PADDLEWIDTH,ptPaddle.y+PADDLEHEIGHT);
  757.  
  758.         //check for collision
  759.         IntersectRect(&rcIntersect,&rcBrick,&rcBall);
  760.  
  761.         //if collision detected
  762.         if(!IsRectEmpty(&rcIntersect))
  763.         {
  764.             //reset the brick hit
  765.             dwBricksHit=0;
  766.  
  767.             //calculate which part of paddle was hit
  768.             x=ptBallNext.x+BALLWIDTH/2-ptPaddle.x;
  769.             if(x<0) x=0;
  770.             if(x>PADDLEWIDTH) x=PADDLEWIDTH-1;
  771.             x/=8;
  772.  
  773.             //set velocites depending on section hit
  774.             switch(x)
  775.             {
  776.             case 0:
  777.                 {
  778.                     ptBallVel.x=-4;
  779.                     ptBallVel.y=-2;
  780.                 }break;
  781.             case 1:
  782.                 {
  783.                     ptBallVel.x=-3;
  784.                     ptBallVel.y=-3;
  785.                 }break;
  786.             case 2:
  787.                 {
  788.                     ptBallVel.x=-2;
  789.                     ptBallVel.y=-4;
  790.                 }break;
  791.             case 3:
  792.                 {
  793.                     ptBallVel.x=-1;
  794.                     ptBallVel.y=-4;
  795.                 }break;
  796.             case 4:
  797.                 {
  798.                     ptBallVel.x=1;
  799.                     ptBallVel.y=-4;
  800.                 }break;
  801.             case 5:
  802.                 {
  803.                     ptBallVel.x=2;
  804.                     ptBallVel.y=-4;
  805.                 }break;
  806.             case 6:
  807.                 {
  808.                     ptBallVel.x=3;
  809.                     ptBallVel.y=-3;
  810.                 }break;
  811.             case 7:
  812.                 {
  813.                     ptBallVel.x=4;
  814.                     ptBallVel.y=-2;
  815.                 }break;
  816.             }
  817.             SoundPlay(SND_BOUNCE);
  818.         }
  819.     }
  820.  
  821.     //update ball position
  822.     ptBall=ptBallNext;
  823. }
  824.  
  825. void SoundPlay(int sound)
  826. {
  827.     //increment the sound copy
  828.     dwSoundCopy[sound]++;
  829.  
  830.     //make sure copy number is in range
  831.     dwSoundCopy[sound]%=SOUNDCOPYCOUNT;
  832.  
  833.     //play sound
  834.     lpdsb[sound][dwSoundCopy[sound]]->Play(0,0,0);
  835. }
  836.  
  837. void ShowScore()
  838. {
  839.     //buffer for converting from DWORD to string
  840.     char Buf[20];
  841.     memset(Buf,0,20);
  842.  
  843.     //convert
  844.     itoa(dwScore,Buf,10);
  845.  
  846.     //set up rectangle
  847.     RECT rcText;
  848.     SetRect(&rcText,0,0,SCREENWIDTH,60);
  849.  
  850.     //grab dc from back buffer
  851.     HDC hdc;
  852.     lpddsback->GetDC(&hdc);
  853.  
  854.     //set font, color, and background mode
  855.     SelectObject(hdc,hfntMain);
  856.     SetTextColor(hdc,RGB(255,255,255));
  857.     SetBkMode(hdc,TRANSPARENT);
  858.  
  859.     //draw the text
  860.     DrawText(hdc,Buf,strlen(Buf),&rcText,DT_RIGHT | DT_TOP | DT_SINGLELINE);
  861.  
  862.     //relese dc to back buffer
  863.     lpddsback->ReleaseDC(hdc);
  864. }
  865.  
  866. void ShowLives()
  867. {
  868.     //source and dest rect
  869.     RECT rcSrc;
  870.     RECT rcDst;
  871.  
  872.     //set up source rect
  873.     SetRect(&rcSrc,0,0,BALLWIDTH,BALLHEIGHT);
  874.     SetRect(&rcDst,0,0,BALLWIDTH,BALLHEIGHT);
  875.  
  876.     //show one ball for each life at upper left of screen
  877.     for(int count=0;count<(int)dwLives;count++)
  878.     {
  879.         //move dest rect to right
  880.         OffsetRect(&rcDst,count*BALLWIDTH,0);
  881.  
  882.         //blit
  883.         lpddsback->Blt(&rcDst,lpddsball,&rcSrc,DDBLT_WAIT | DDBLT_KEYSRC,NULL);
  884.  
  885.         //move dest rect back to left
  886.         OffsetRect(&rcDst,-count*BALLWIDTH,0);
  887.     }
  888. }